function log(s) {
/*
	if(console && console.log)
		console.log(s);
*/
}

function days_between(date1, date2) {

    // The number of milliseconds in one day
    var ONE_DAY = 1000 * 60 * 60 * 24

    // Convert both dates to milliseconds
    var date1_ms = date1.getTime()
    var date2_ms = date2.getTime()

    // Calculate the difference in milliseconds
    var difference_ms = Math.abs(date1_ms - date2_ms)
    
    // Convert back to days and return
    return Math.round(difference_ms/ONE_DAY)

}

function floorInBase(n, base) {
    return base * Math.floor(n / base);
}

function round(n, base) {
    return Math.round(n * base) / base;
}

function traffic(n) {
	if(typeof(n) == 'number' || n.match(/\d+/)){
		n = n-0;
		if(n>=1048576) 
			res = ""+round(n/1048576, 100)+"&nbsp;GB";
		else if(n>=1024) 
			res = ""+round(n/1024, 100)+"&nbsp;MB";
		else
			res = ""+n+"&nbsp;KB";
		return '<span title="'+n+'&nbsp;KB">'+res+'</span>';
	} else
		return n;
}

function showData(tabIndex, dataType) {
	var tab = $('#tab-'+tabIndex);
	var table = tab.find('.table:first');
	var graph = tab.find('.graph:first');
	
	var tbl = 
'<table id="data_table" class="list leaf_full">'+
	'<thead>'+
		'<tr>'+
			'<th class="list">'+period[dataType].text+'</th>'+
			'<th class="list numeric">Прием</th>'+
			'<th class="list numeric">Передача</th>'+
			'<th class="list numeric">Отношение</th>'+
			'<th class="list numeric">Всего</th>'+
		'</tr>'+
	'</thead>'+
	'<tbody>';
	
	var dataRaw;
	if(xml.interface[tabIndex].traffic[dataType]){
		dataRaw = xml.interface[tabIndex].traffic[dataType][period[dataType].single];
		if(dataRaw[0] === undefined) dataRaw = [dataRaw];
	} else 
		dataRaw = [];
	
	var data = [];
	for(i in dataRaw) {
		data[dataRaw[i]['@id']] = dataRaw[i];
	}
	
	var rx = [];
	var tx = [];
	var ticks = [];
	var labels = [];
	if(dataType == 'hours'){
		var sh = (xml.interface[tabIndex].updated.time.hour-0+25)%24;
		for(i=0;i<=23;i++,sh=(sh+1)%24) {
			rx.push([i, (data[sh]?data[sh].rx-0:0)]);
			tx.push([i, (data[sh]?data[sh].tx-0:0)]);
			ticks.push([i, (sh<10?'0':'')+sh])
			labels.push((sh<10?'0':'')+sh+':00');
		}
	}else if(dataType == 'days'){
		for(i=29;i>=0;i--) {
			if(dataRaw[i]) {
				rx.push([29-i, dataRaw[i].rx-0]);
				tx.push([29-i, dataRaw[i].tx-0]);
				ticks.push([29-i, dataRaw[i].date.day-0]);
				labels.push(dataRaw[i].date.day+'.'+dataRaw[i].date.month+'.'+dataRaw[i].date.year);
			} else {
				rx.push([29-i, 0]);
				tx.push([29-i, 0]);
				ticks.push([29-i, '']);
				labels.push('-');
			}
		}
	}else if(dataType == 'months') {
		for(i=11;i>=0;i--) {
			if(dataRaw[i]) {
				rx.push([11-i, dataRaw[i].rx-0]);
				tx.push([11-i, dataRaw[i].tx-0]);
				ticks.push([11-i, dataRaw[i].date.month-0]);
				labels.push(months[dataRaw[i].date.month-1]+' '+dataRaw[i].date.year);
			} else {
				rx.push([11-i, 0]);
				tx.push([11-i, 0]);
				ticks.push([11-i, '']);
				labels.push('-');
			}
		}
	}else if(dataType == 'tops') {
		for(i=0;i<=9;i++) {
			if(dataRaw[i]) {
				rx.push([i, dataRaw[i].rx-0]);
				tx.push([i, dataRaw[i].tx-0]);
				ticks.push([i, i+1]);
				labels.push("#"+(i+1)+" "+dataRaw[i].date.day+'.'+dataRaw[i].date.month+'.'+dataRaw[i].date.year+", "+dataRaw[i].time.hour+':'+dataRaw[i].time.minute);
			} else {
				break;
			}
		}
	}
		
	var i = 1;
	var output_started = false;
	for(index in labels) {
		if(!output_started && labels[index] == '-') continue;
		tbl +=
		'<tr class="row_'+index+' '+(i==0?'first':'')+' '+(i%2?'even':'odd')+'">'+
			'<td class="list narrow">'+labels[index]+'</td>'+
			'<td class="list narrow numeric">'+traffic(rx[index][1])+'</td>'+
			'<td class="list narrow numeric">'+traffic(tx[index][1])+'</td>'+
			'<td class="list narrow numeric">'+(tx[index][1]>0?round(rx[index][1]/tx[index][1], 100):'-')+'</td>'+
			'<td class="list narrow numeric">'+(rx[index][1]!='-'&&tx[index][1]!='-'?traffic(rx[index][1]+tx[index][1]):'-')+'</td>'+
		'</tr>';
		output_started = true;
		i++;
	}

	tbl +=
	'</tbody>'+
'</table>';
	table.empty().append(tbl);
	
	var previousPoint = null;
	$.plot(graph, [
        { label: "Прием",  data: rx, bars: { show: true, align: 'center'} },
        { label: "Передача",  data: tx, bars: { show: true, align: 'center'} }
    ], {
    	grid: { 
    		hoverable: true, 
    		autoHighlight: false
/*     		clickable: true  */
    	},
    	legend: {
    		noColumns: 2
    	},
		xaxis: {
            ticks: ticks
        },
        yaxis: {
//        	tickSize: 102400,
        	tickFormatter: traffic,
        	ticks: function (axis){
                var ticks = [];
                var numTicks = 4;
				var delta = (axis.max-axis.min)/numTicks;
				var dec = Math.floor(Math.log(delta) / Math.LN2);
				var magn = Math.pow(2, dec);
				var norm = delta / magn;
				var size;
				if(norm < 0.5)
					size = 0.5;
				else if(norm < 1.7)
					size = 1;
				else 
					size = 2;
				var tickSize = magn*size;
//				tickSize = 102400;
                // spew out all possible ticks
                var start = floorInBase(axis.min, tickSize),
                    i = 0, v = Number.NaN, prev;
                do {
                    prev = v;
                    v = start + i * tickSize;
                    ticks.push(v);
                    ++i;
                } while (v < axis.max && v != prev);
                return ticks;
            }
        }    	
    });
    graph.unbind('plothover').bind('plothover', function (event, pos, item) {
		if (item) {
		    if (previousPoint != item.dataIndex) {
				var i = item.dataIndex	;
	            previousPoint = item.dataIndex;
	            
	            $("#tooltip").remove();
				$('#data_table tr').removeClass('highlight');
				$('.row_'+i).addClass('highlight');
	            showTooltip(pos.pageX, pos.pageY,
	            	"<dl>"+
	            		"<dt>"+period[dataType].label+"</dt><dd>"+labels[i]+"</dd>"+
	            		"<dt>Прием</dt><dd>"+traffic(rx[i][1])+"</dd>"+
	            		"<dt>Передача</dt><dd>"+traffic(tx[i][1])+"</dd>"+
	            	"</dl>"
	            );
	        }
	    } else {
			$('#data_table tr').removeClass('highlight');
	        $("#tooltip").remove();
	        previousPoint = null;            
	    }    	
	});
	
}

function showTooltip(x, y, contents) {
    $('<div id="tooltip"><div class="tooltipInner">' + contents + '</div></div>').css( {
        display: 'none',
        top: y + 5,
        left: x + 5,
    }).appendTo("body").fadeIn(200);
}



var interfaces = {
	'eth2.2': 'WAN eth2.2',
	'eth2.1': 'LAN eth2.1',
	'ra0': 'LAN WiFi ra0',
	'wimax0': 'WAN wimax wimax0',
	'br0': 'LAN объединенный br0'
};

var period = {
	'hours': {text: 'Часы', label: 'Время', single: 'hour'},
	'days': {text: 'Дни', label: 'День', single: 'day'},
	'months': {text: 'Месяцы', label: 'Месяц', single: 'month'},
	'tops': {text: 'Топ', label: 'Топ', single: 'top'}
}

var months = ['январь', 'февраль', 'март', 'апрель', 'май', 'июнь', 'июль', 'август', 'сентябрь', 'октябрь', 'ноябрь', 'декабрь'];

var xml;
$(function () {
	$.ajax("http://"+document.domain+":81/addons/vnstat/vnstat.cgi", {
		dataType: 'xml',
		success:
			function (data) {
				//var 
				xml = xml2obj(data);
				var tab_headers = '<ul>';
				var tab_bodies = '';
				
				if(xml.interface === undefined) { // нет ни одного интерфейса в выводе vnstat
					$('#content').removeClass('loader').html(
						"<center>Нет базы данных мониторинга vnstat</center>"+
						"<center>Чтобы создать базу vnstat для сетевого интерфейса</center>"+
						"<center>и начать мониторинг выполните команду</center>"+
						"<center><i>vnstat -u -i eth2.2</i></center>"+
						"<center>Вместо eth2.2 напишите имя интерфейса который нужно мониторить</center>"+
						"<center>Пример интерфейсов: ra0 eth2.1 eth2.2 br0</center>"
					);	
					return false;
				}
				
				if(xml.interface[0] === undefined) xml.interface = [xml.interface];
				$.each(xml.interface, function (index) {
					var interface = this;
					var interface_name;
					if(interface.nick != interface.id)
						interface_name = interface.nick;
					else
						interface_name = interfaces[interface.id] || interface.id;
						
					tab_headers += '<li><a href="#tab-'+index+'" id="tab-header-'+interface.id+'">'+interface_name+'</a></li>';
					tab_bodies += '<div id="tab-'+index+'" data-id="'+index+'" class="tab">';
					
					var created = interface.created.date;
					var updated = interface.updated.date;
					var updated_time = interface.updated.time;
					var created_date = new Date(created.year, created.month-1, created.day);
					
					tab_bodies += 
					'<div class="left-column">'+
						'<div class="interface-info interface-panel">'+
							'<h2>Мониторинг</h2>'+
							'<dl>'+
								'<dt>Начало мониторинга</dt><dd>'+created.day+'.'+created.month+'.'+created.year+'</dd>'+
								'<dt>Дата обновления</dt><dd>'+updated_time.hour+':'+updated_time.minute+' '+updated.day+'.'+updated.month+'.'+updated.year+'</dd>'+
								'<dt>Версия vnstat</dt><dd>'+xml['@version']+'</dd>'+
							'</dl>'+
						'</div>'+
						'<div class="interface-total interface-panel">'+
							'<h2>Суммарный трафик</h2>'+
							'<dl>'+
								'<dt>Принято</dt><dd>'+traffic(interface.traffic.total.rx)+'</dd>'+
								'<dt>Передано</dt><dd>'+traffic(interface.traffic.total.tx)+'</dd>'+
								'<dt>За</dt><dd>'+days_between(created_date, new Date())+' дн.</dd>'+
							'</dl>'+
						'</div>'+
					'</div>'+
					'<div class="right-column">'+
						'<div class="period">'+
							'<ul>'+
								'<li id="hours" class="active">Часы</li>'+
								'<li id="days">Дни</li>'+
								'<li id="months">Месяцы</li>'+
								'<li id="tops">Топ</li>'+
							'</ul>'+
						'</div>'+
						'<div class="graph_bg"><div class="graph"></div></div>'+
						'<div class="table"></div>'+
						'<div class="clear"></div>'+
					'</div>'+
					'';
								
					
					tab_bodies += '<div class="clear"></div></div>';
				});
				tab_headers += '</ul>';
				
				$('#tabs').append(tab_headers+tab_bodies).tabs({
					selected: 0,
					show: function (event, ui) {
						if(!$(ui.panel).data('init')) {
							setTimeout("showData("+ui.index+", 'hours')", 100);
							$(ui.panel).data('init', true);
						}
					}
				}).show();
		
				$('.period li').click(function () {
					e = $(this);
					e.parent().find('li.active').removeClass('active');
					e.addClass('active');
					showData(e.parents('.tab').data('id'), this.id);
				});
		
		//		showData(0, 'hours');
				$('#content').removeClass('loader');		
			}
	});
})


/*	This work is licensed under Creative Commons GNU LGPL License.

	License: http://creativecommons.org/licenses/LGPL/2.1/
   Version: 0.9
	Author:  Stefan Goessner/2006
	Web:     http://goessner.net/ 
*/
function xml2obj(xml, tab) {
   var X = {
      toObj: function(xml) {
         var o = {};
         if (xml.nodeType==1) {   // element node ..
            if (xml.attributes.length)   // element with attributes  ..
               for (var i=0; i<xml.attributes.length; i++)
                  o["@"+xml.attributes[i].nodeName] = (xml.attributes[i].nodeValue||"").toString();
            if (xml.firstChild) { // element has child nodes ..
               var textChild=0, cdataChild=0, hasElementChild=false;
               for (var n=xml.firstChild; n; n=n.nextSibling) {
                  if (n.nodeType==1) hasElementChild = true;
                  else if (n.nodeType==3 && n.nodeValue.match(/[^ \f\n\r\t\v]/)) textChild++; // non-whitespace text
                  else if (n.nodeType==4) cdataChild++; // cdata section node
               }
               if (hasElementChild) {
                  if (textChild < 2 && cdataChild < 2) { // structured element with evtl. a single text or/and cdata node ..
                     X.removeWhite(xml);
                     for (var n=xml.firstChild; n; n=n.nextSibling) {
                        if (n.nodeType == 3)  // text node
                           o["#text"] = X.escape(n.nodeValue);
                        else if (n.nodeType == 4)  // cdata node
                           o["#cdata"] = X.escape(n.nodeValue);
                        else if (o[n.nodeName]) {  // multiple occurence of element ..
                           if (o[n.nodeName] instanceof Array)
                              o[n.nodeName][o[n.nodeName].length] = X.toObj(n);
                           else
                              o[n.nodeName] = [o[n.nodeName], X.toObj(n)];
                        }
                        else  // first occurence of element..
                           o[n.nodeName] = X.toObj(n);
                     }
                  }
                  else { // mixed content
                     if (!xml.attributes.length)
                        o = X.escape(X.innerXml(xml));
                     else
                        o["#text"] = X.escape(X.innerXml(xml));
                  }
               }
               else if (textChild) { // pure text
                  if (!xml.attributes.length)
                     o = X.escape(X.innerXml(xml));
                  else
                     o["#text"] = X.escape(X.innerXml(xml));
               }
               else if (cdataChild) { // cdata
                  if (cdataChild > 1)
                     o = X.escape(X.innerXml(xml));
                  else
                     for (var n=xml.firstChild; n; n=n.nextSibling)
                        o["#cdata"] = X.escape(n.nodeValue);
               }
            }
            if (!xml.attributes.length && !xml.firstChild) o = null;
         }
         else if (xml.nodeType==9) { // document.node
            o = X.toObj(xml.documentElement);
         }
         else
            alert("unhandled node type: " + xml.nodeType);
         return o;
      },
      toJson: function(o, name, ind) {
         var json = name ? ("\""+name+"\"") : "";
         if (o instanceof Array) {
            for (var i=0,n=o.length; i<n; i++)
               o[i] = X.toJson(o[i], "", ind+"\t");
            json += (name?":[":"[") + (o.length > 1 ? ("\n"+ind+"\t"+o.join(",\n"+ind+"\t")+"\n"+ind) : o.join("")) + "]";
         }
         else if (o == null)
            json += (name&&":") + "null";
         else if (typeof(o) == "object") {
            var arr = [];
            for (var m in o)
               arr[arr.length] = X.toJson(o[m], m, ind+"\t");
            json += (name?":{":"{") + (arr.length > 1 ? ("\n"+ind+"\t"+arr.join(",\n"+ind+"\t")+"\n"+ind) : arr.join("")) + "}";
         }
         else if (typeof(o) == "string")
            json += (name&&":") + "\"" + o.toString() + "\"";
         else
            json += (name&&":") + o.toString();
         return json;
      },
      innerXml: function(node) {
         var s = ""
         if ("innerHTML" in node)
            s = node.innerHTML;
         else {
            var asXml = function(n) {
               var s = "";
               if (n.nodeType == 1) {
                  s += "<" + n.nodeName;
                  for (var i=0; i<n.attributes.length;i++)
                     s += " " + n.attributes[i].nodeName + "=\"" + (n.attributes[i].nodeValue||"").toString() + "\"";
                  if (n.firstChild) {
                     s += ">";
                     for (var c=n.firstChild; c; c=c.nextSibling)
                        s += asXml(c);
                     s += "</"+n.nodeName+">";
                  }
                  else
                     s += "/>";
               }
               else if (n.nodeType == 3)
                  s += n.nodeValue;
               else if (n.nodeType == 4)
                  s += "<![CDATA[" + n.nodeValue + "]]>";
               return s;
            };
            for (var c=node.firstChild; c; c=c.nextSibling)
               s += asXml(c);
         }
         return s;
      },
      escape: function(txt) {
         return txt.replace(/[\\]/g, "\\\\")
                   .replace(/[\"]/g, '\\"')
                   .replace(/[\n]/g, '\\n')
                   .replace(/[\r]/g, '\\r');
      },
      removeWhite: function(e) {
         e.normalize();
         for (var n = e.firstChild; n; ) {
            if (n.nodeType == 3) {  // text node
               if (!n.nodeValue.match(/[^ \f\n\r\t\v]/)) { // pure whitespace text node
                  var nxt = n.nextSibling;
                  e.removeChild(n);
                  n = nxt;
               }
               else
                  n = n.nextSibling;
            }
            else if (n.nodeType == 1) {  // element node
               X.removeWhite(n);
               n = n.nextSibling;
            }
            else                      // any other node
               n = n.nextSibling;
         }
         return e;
      }
   };
   if (xml.nodeType == 9) // document node
      xml = xml.documentElement;
   return X.toObj(xml);
/*
   var json = X.toJson(X.toObj(X.removeWhite(xml)), xml.nodeName, "\t");
   return "{\n" + tab + (tab ? json.replace(/\t/g, tab) : json.replace(/\t|\n/g, "")) + "\n}";
*/
}
